/**
 * Copyright (C),2011-2012,北京国电通网络技术有限公司.
 * FileName:	serial.cpp
 * Author:		LiuHaifeng
 * Version:		V0.1
 * Date:		2011-11-15
 * Description	This file realizes serial operation, include open/read/write
 */

/**
 * History:
 * 		Author		date		Version		Description
 */

#include "serial.h"
#include "../sqlite/sqlite.h"







extern struct StDataTransmit g_dataTrans;
extern struct StSerialFD g_serialFD;
extern struct StLED g_LED;
extern int setLed_ON;
extern int setLed_OFF;

static int setSpeed(int,int);
static int setDataFormat(int,int, int, int);

/***openPort() brief open serial port and set some attribute.
 * param comport[in], the number port will be open;
 * param speed[in], the speed of serial;eg:B115200/B9600
 * param databits[in], the bit number per frame;
 * param stopbits[in], the number of stop bits;
 * param parity[in], the type of checksum.
 *
 * retval int, fd if success or -1 failed;
 ***/
int openPort(int comport,int speed,int databits, int stopbits, int parity)
{
	int l_fd=-1;												///temporary parameter
	switch(comport)												///open()
	{
	case 0:
		l_fd=open(DEV_TTY_0,O_RDWR|O_NDELAY|O_NOCTTY);
		break;
	case 1:
		l_fd=open(DEV_TTY_1,O_RDWR|O_NDELAY|O_NOCTTY);
		break;
	case 2:
		l_fd=open(DEV_TTY_2,O_RDWR|O_NDELAY|O_NOCTTY);
		break;
	case 3:
		l_fd=open(DEV_TTY_3,O_RDWR|O_NDELAY|O_NOCTTY);
		break;
	}

	if(-1==l_fd)
	{
		printf("ttyS %d open failed!",comport);
		return -1;
	}
	if(-1==setSpeed(l_fd,speed))								///set speed
	{
		printf("ttyS setSpeed:%d failed!",speed);
		return -1;
	}
	sleep(1);
	if(-1==setDataFormat(l_fd,databits, stopbits, parity))		///set other attribute
	{
		ERROROUT("ttyS setDataFormat failed!");
		return -1;
	}
	sleep(1);													///sleep 1s, wait open and set job end.

	return l_fd;
}
/***setSpeed() brief set speed of serial
 * param fd[in], file descriptor;
 * param speed[in], the speed will be set;
 *
 * retval int, 0 success or -1 failed;
 ***/
static int setSpeed(int fd,int speed)
{
	struct termios l_Opt; 		///important struct in serial setting

	assert(fd>0);

	tcgetattr(fd, &l_Opt); 		///get attribution of serial, put into opt, if successful return 0 or failed return -1
	cfmakeraw(&l_Opt);
#ifdef FREESCALE
	l_Opt.c_cflag|=(speed|CLOCAL |CREAD);              ////?????add by liufuguo for freescale
#endif
	cfsetispeed(&l_Opt,speed);	///set input speed of serial
	cfsetospeed(&l_Opt,speed);	///set output speed of serial

	///set attribute，TCSANOW  make change immediately
	///TCSADRAIN ;make will be change after all output is done
	///TCSAFLUSH ;after all output is done, change will be make; all the input will be delete after that
	tcflush(fd,TCIOFLUSH); 		///clear buffer of input and output
	if (tcsetattr(fd,TCSANOW,&l_Opt)!= 0)
	{
		ERROROUT("tcsetattr() failed!");
		return -1;
	}

	return 0;
}

/***setDataFormat() brief set data format for serial port
 * param fd[in], file descriptor;
 * param databits[in], bit number per frame;
 * param stopbits[in], number of stop bit;
 * param parity[in], checksum type;
 *
 * retval int, return value--0 if true;
 ***/
static int setDataFormat(int fd,int databits, int stopbits, int parity)
{
	struct termios l_opt;

	if (tcgetattr(fd,&l_opt)!= 0)
	{
		ERROROUT("tcgetattr() failed!");
		return -1;
	}

	l_opt.c_cflag &= ~CSIZE;					///set data bit number
	switch(databits)
	{
	case 5:
		l_opt.c_cflag |=CS5;
		break;
	case 6:
		l_opt.c_cflag |=CS6;
		break;
	case 7:
		l_opt.c_cflag |=CS7;
		break;
	case 8:
		l_opt.c_cflag |=CS8;
		break;
#ifdef SMARTHOME_DEBUG
	default:
		ERROROUT("Unsupported data size!");
		return -1;
#endif
	}

	switch(parity)								///set parity
	{
	case 'n':
	case 'N':
		l_opt.c_cflag &= ~PARENB;   			///Clear parity enable
		l_opt.c_iflag &= ~INPCK;    			///Enable parity checking
		break;
	case 'o':									///odd check---"ji"
	case 'O':
		l_opt.c_cflag |= (PARODD|PARENB);		///parity checking
		l_opt.c_iflag |= INPCK;          		///Disnable parity checking
		break;
	case 'e':									///even check---"ou"
	case 'E':
		l_opt.c_cflag |= PARENB;				///Enable parity
		l_opt.c_cflag &= ~PARODD;				///Odd parity
		l_opt.c_iflag |= INPCK;	    			///Disable parity checking
		break;
#ifdef SMARTHOME_DEBUG
	default:
		ERROROUT("Unsupported parity!");
		return -1;
#endif
	}

	if( stopbits == 1 )							///set stopbits
		l_opt.c_cflag &= ~CSTOPB;
	else if ( stopbits == 2 )
		l_opt.c_cflag |= CSTOPB;

	l_opt.c_cc[VTIME] = 100;					///set the min wait time and wait bytes to 100 indicate:must set.
	l_opt.c_cc[VMIN] = 0;

	tcflush(fd,TCIFLUSH);						///clear input and output buffer

	if(tcsetattr(fd,TCSANOW,&l_opt)!= 0)		///set the new attribute
	{
		ERROROUT("tcsetattr() failed!");
		return -1;
	}
	return 0;
}
/***sendSerial() brief send data to serial port
 * param length[in], file descriptor of serial port to be send data
 *
 * retval int, return value--true if true,false failed.
 ***/
bool sendSerial(int length)
{
	int l_fd=-1;								///temporary file descriptor

#if defined SMARTHOME_DEBUG
#ifdef DEBUG_PC
	l_fd=g_serialFD.st_serial0;
#elif defined DEBUG_SOCKET
	l_fd=g_serialFD.st_serial1;
#elif defined DEBUG_ARM
	if(g_dataTrans.st_sendSerial[0]==0x68)
	{
		l_fd=g_serialFD.st_serial1;
	}
	else if(g_dataTrans.st_sendSerial[0]==0x0b || g_dataTrans.st_sendSerial[0]==0x09)
	{
		l_fd=g_serialFD.st_serial2;
	}
	else
	{
		ERROROUT("no this format command.");
		return false;
	}
#endif
#elif defined NO_DEBUG_SOCKET
	l_fd=g_serialFD.st_serial1;
#elif defined NO_DEBUG_ALL
	if(g_dataTrans.st_sendSerial[0]==0x68)
	{
		l_fd=g_serialFD.st_serial1;
	}
	else if(g_dataTrans.st_sendSerial[0]==0x0b)
	{
		l_fd=g_serialFD.st_serial3;
	}
	else
	{
		ERROROUT("no this format command.");
		return false;
	}
#endif

///turn on mod2
#ifndef DEBUG_PC
	if(g_LED.st_mod2 >= 0)
	{
		#ifdef FREESCALE
			write(g_LED.st_mod2,&setLed_ON,1);
		#else
			ioctl(g_LED.st_mod2, SET_LED_ON, NULL);
		#endif
	}
#endif
	for(int i=0;i<length;i++)
		LOGI("%02x\t",g_dataTrans.st_sendSerial[i]);
	///send data
#if defined SMARTHOME_DEBUG
    printf("begin send data to serial.\n");
	for(int i=0;i<length;i++)
		printf("%02x\t",g_dataTrans.st_sendSerial[i]);
	printf("\n");
	///data writed to serial save in database.
    printf("end send data to serial.\n");

	saveComInDatabase(g_dataTrans.st_sendSerial,length,true);
#endif

///turn off mod2
#ifndef DEBUG_PC
	if(g_LED.st_mod2 >= 0)
	{
		#ifdef FREESCALE
			write(g_LED.st_mod2,&setLed_OFF,1);
		#else
			ioctl(g_LED.st_mod2, SET_LED_OFF, NULL);
		#endif
	}
#endif

	if(write(l_fd,g_dataTrans.st_sendSerial,length)!=length)
	{
		ERROROUT("write() error!");
		tcflush(l_fd,TCOFLUSH);						///???bug(maybe cause some problem)???flushes data written but not transmitted.
		return false;
	}


	return true;
}
